#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#include "msq.h"

// 初始化队列
void init_queue(MsgQueue *q) {
    printf("Initializing queue...\n");
    q->head = q->tail = q->count = 0;
    pthread_mutex_init(&q->mutex, NULL);
    pthread_cond_init(&q->not_empty, NULL);
    pthread_cond_init(&q->not_full, NULL);
}

// 入队（阻塞）
void enqueue(MsgQueue *q, int value) {
    printf("Enqueueing, try to get lock...\n");
    pthread_mutex_lock(&q->mutex);
    printf("Greate! Get lock\n");
    while (q->count == QUEUE_SIZE) {
        printf("queue is full, so wait...\n");
        // 队列满，等待 not_full 条件变量
        pthread_cond_wait(&q->not_full, &q->mutex);
        printf("I find new empty slot is in the queue, I will entry it!\n");
    }
    q->buffer[q->tail] = value;
    q->tail = (q->tail + 1) % QUEUE_SIZE;
    q->count++;
    pthread_cond_signal(&q->not_empty); // 唤醒消费者
    pthread_mutex_unlock(&q->mutex);
    printf("enqueue end!\n");
}

// 出队（阻塞）
int dequeue(MsgQueue *q) {
    printf("dequeue, try to get the lock...\n"); 
    pthread_mutex_lock(&q->mutex);
    printf("Greate! Get lock\n");
    while (q->count == 0) {
        printf("queue is empty, so wait...\n");
        // 队列空，等待 not_empty 条件变量
        pthread_cond_wait(&q->not_empty, &q->mutex);
    }
    int value = q->buffer[q->head];
    q->head = (q->head + 1) % QUEUE_SIZE;
    q->count--;
    pthread_cond_signal(&q->not_full); // 唤醒生产者
    pthread_mutex_unlock(&q->mutex);
    printf("dequeue end\n");

    return value;
}

// 示例生产者线程
void *producer(void *arg) {
    MsgQueue *q = (MsgQueue *)arg;
    for (int i = 0; i < 100; i++) {
        enqueue(q, i);
        printf("Produced: %d\n", i);
        usleep(100000); // 模拟耗时
    }

    sleep(10);

    // for (int i = 0; i < 5; i++) {
    //     enqueue(q, i);
    //     printf("Produced: %d\n", i);
    //     usleep(100000); // 模拟耗时
    // }

    return NULL;
}

// 示例消费者线程
void *consumer(void *arg) {
    MsgQueue *q = (MsgQueue *)arg;
    for (int i = 0; i < 5; i++) {
        int value = dequeue(q);
        printf("Consumed: %d\n", value);
        usleep(150000); // 模拟处理时间
    }

    sleep(10);

    for (int i = 0; i < 5; i++) {
        int value = dequeue(q);
        printf("Consumed: %d\n", value);
        usleep(150000); // 模拟处理时间
    }

    return NULL;
}

int main() {
    MsgQueue queue;
    init_queue(&queue);

    pthread_t t1, t2;
    pthread_create(&t1, NULL, producer, &queue);
    pthread_create(&t2, NULL, consumer, &queue);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return 0;
}
